﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Threading.Tasks;

namespace Link_eLab.JwtAuthorizePolicy.Extension
{
    /// <summary>
    /// 权限授权Handler
    /// </summary>
    public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
    {
        /// <summary>
        /// 验证方案提供对象
        /// </summary>
        public IAuthenticationSchemeProvider Schemes { get; set; }

        /// <summary>
        /// Accessor
        /// </summary>
        private IHttpContextAccessor Accessor { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="schemes"></param>
        /// <param name="accessor"></param>
        public PermissionHandler(IAuthenticationSchemeProvider schemes, IHttpContextAccessor accessor)
        {
            Schemes = schemes;
            Accessor = accessor;
        }

        /// <summary>
        /// HandleRequirementAsync
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requirement"></param>
        /// <returns>JSON结果集</returns>
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
        {
            // 调试时可跳过验证
            if (!"True".Equals(requirement.OpenJwt))
            {
                context.Succeed(requirement);
                return;
            }

            // 从AuthorizationHandlerContext转成HttpContext，以便取出表求信息
            //var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;
            var httpContext = Accessor.HttpContext;
            // 请求Url
            var questUrl = httpContext.Request.Path.Value.ToLower();

            // 判断请求是否停止
            var handlers = httpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
            foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
            {
                if (await handlers.GetHandlerAsync(httpContext, scheme.Name) is IAuthenticationRequestHandler handler && await handler.HandleRequestAsync())
                {
                    context.Fail();
                    return;
                }
            }

            // 判断请求是否拥有凭据，即有没有登录
            var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();

            if (defaultAuthenticate != null)
            {
                var result = await httpContext.AuthenticateAsync(defaultAuthenticate.Name);
                // result?.Principal不为空即登录成功
                if (result?.Principal != null)
                {
                    httpContext.User = result.Principal;

                    string clientType = string.Empty;
                    string userId = string.Empty;
                    string orgId = string.Empty;
                    string agencyId = string.Empty;
                    string userName = string.Empty;
                    double exp = 0;

                    foreach (var a in httpContext.User.Claims)
                    {
                        switch (a.Type)
                        {
                            case "clientType":
                                clientType = a.Value;
                                break;
                            case "userId":
                                userId = a.Value;
                                break;
                            case "orgId":
                                orgId = a.Value;
                                break;
                            case "agencyId":
                                agencyId = a.Value;
                                break;
                            case "userName":
                                userName = a.Value;
                                break;
                            case "exp":
                                exp = Convert.ToDouble(a.Value);
                                break;
                            default:
                                break;
                        }
                    }

                    // 当地时区
                    DateTime startTime = Convert.ToDateTime(new DateTime(1970, 1, 1));
                    DateTime expDate = startTime.AddSeconds(exp).AddHours(8);

                    if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(clientType))
                    {
                        context.Fail();
                        return;
                    }

                    // 根据clientType判断是否需要校验url权限  saas平台的需要校验url权限
                    // todo 根据自己的权限逻辑编写验证代码

                    // 判断过期时间
                    if (expDate >= DateTime.Now)
                    {
                        context.Succeed(requirement);
                    }
                    else
                    {
                        context.Fail();
                    }
                    return;
                }
            }

            // 判断没有登录时，是否访问登录的url，并且是Post请求，并且是form表单提交类型，否则为失败
            if (!questUrl.Equals(requirement.LoginPath.ToLower(), StringComparison.Ordinal) && (!"POST".Equals(httpContext.Request.Method)
                || !httpContext.Request.HasFormContentType))
            {
                context.Fail();
                return;
            }
            context.Succeed(requirement);
        }

    }
}